﻿using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Context;
using NHibernate.Tool.hbm2ddl;
using Shake.Domain.Infrastructures;
using Shake.Framework.Infrastructure;
using Shake.Framework.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;


namespace Shake.Framework.Repository
{
    public class Repository : IRepository
    {
        public void Delete<T>(T entity) where T : ShakeEntity
        {
            WorkTransaction(s => s.Delete(entity));
        }

        public void DeleteMany<T>(IEnumerable<T> entities) where T : ShakeEntity
        {
            WorkTransaction(s => entities.ToList().ForEach(t => s.Delete(t)));
        }

        public void Insert<T>(T entity) where T : ShakeEntity
        {
            WorkTransaction(s => s.Save(entity));

        }

        public void InsertMany<T>(IEnumerable<T> entities) where T : ShakeEntity
        {
            WorkTransaction(s => entities.ToList().ForEach(t => s.Save(t)));
        }

        public void Update<T>(T entity) where T : ShakeEntity
        {
            WorkTransaction(s => s.Update(entity));
        }

        public void UpdateMany<T>(IEnumerable<T> entities) where T : ShakeEntity
        {
            WorkTransaction(s => entities.ToList().ForEach(t => s.Update(t)));
        }

        public ISessionFactory CreateSessionFactory()
        {
            var msSqlConfiguration = MsSqlConfiguration.MsSql2012.ShowSql().ConnectionString(cnf => cnf.FromConnectionStringWithKey("DefaultConnection"));
            var factory = Fluently.Configure().Database(msSqlConfiguration)
                .CurrentSessionContext<WebSessionContext>()
                .Mappings(cnf =>
                {
                    // TODO: 写入缓存
                    cnf.FluentMappings.AddFromAssembly(Shake.Domain.DomainRegister.GetAssembly());
                    cnf.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly());
                })
               .BuildSessionFactory();

            if (!CurrentSessionContext.HasBind(factory))
            {
                CurrentSessionContext.Bind(factory.OpenSession());
            }

            return factory;
        }

        private void WorkTransaction(Action<ISession> action)
        {
            var factory = CreateSessionFactory();
            using (var session = factory.GetCurrentSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    action.Invoke(session);
                    transaction.Commit();
                }
            }
        }

        private static void Migration(NHibernate.Cfg.Configuration config)
        {
            //new SchemaUpdate(config).Execute(true, true);
        }


        public IList<T> Query<T>() where T : ShakeEntity
        {
            var factory = CreateSessionFactory();
            using (var session = factory.GetCurrentSession())
            {
                return session.CreateCriteria<T>().List<T>();
            }
        }
    }
}
